import { Node, Sprite, UIOpacity, UITransform, Vec2, Vec3, tween, color, misc } from "cc";
import { Global } from "./Global";

export class Tools {

    /**
     * 
     * @param pos 坐标
     * @param transform 是否在tran范围内
     * @param out 如果在范围内会导出被移至范围边界的坐标
     * @returns 
     */
    public static IsPositionInTransform(
        pos: Vec2 | Vec3,
        transform: UITransform,
        out?: Vec3 //导出移到边界的坐标
    ): boolean {
        // Convert Vec2 to Vec3 if needed
        let position = pos instanceof Vec2 ? new Vec3(pos.x, pos.y, 0) : pos;

        // Convert the world position to the node's local position
        const localPos = new Vec3();
        // transform.node.inverseTransformPoint(localPos, position);
        transform.convertToNodeSpaceAR(position, localPos)
        let scale = Vec2.ONE;//transform.node.scale;

        // Get the content size and anchor point
        const contentSize = transform.contentSize;
        const anchorPoint = transform.anchorPoint;

        // Calculate the anchor offset
        const anchorOffsetX = contentSize.width * scale.x * anchorPoint.x;
        const anchorOffsetY = contentSize.height * scale.y * anchorPoint.y;

        // Calculate the bounds of the transform
        const minX = -anchorOffsetX;
        const maxX = contentSize.width * scale.x - anchorOffsetX;
        const minY = -anchorOffsetY;
        const maxY = contentSize.height * scale.y - anchorOffsetY;

        // Check if the local position is within the bounds
        const isInBounds = localPos.x >= minX && localPos.x <= maxX && localPos.y >= minY && localPos.y <= maxY;

        if (isInBounds) {
            let adjustX = localPos.x - minX > maxX - localPos.x ? maxX - localPos.x : minX - localPos.x;
            let adjustY = localPos.y - minY > maxY - localPos.y ? maxY - localPos.y : minY - localPos.y;

            if (Math.abs(adjustX) > Math.abs(adjustY)) {
                localPos.y += adjustY;
            }
            else {
                localPos.x += adjustX;
            }
        }

        transform.convertToWorldSpaceAR(localPos, out);

        return isInBounds;
    }


    public static IsPositionInScreen(pos: Vec2 | Vec3) {
        let position = pos instanceof Vec2 ? new Vec3(pos.x, pos.y, 0) : pos;
        let screenCenter = Global.gameManager.node.getWorldPosition();
        let screenSize = Global.designScreenSize;//随摄像机视角影响
        screenSize.width *= Global.CameraOrthoScale;
        screenSize.height *= Global.CameraOrthoScale;

        let space = 10 * Global.CameraOrthoScale;

        //如果项目勾选了适配高度就不用手动修改适配了
        //如果项目都勾选了，，就是另一种情况，此时获取到的窗口大小并不是相机所看到的屏幕大小
        let left = screenCenter.x - screenSize.width * Global.screenAdjustScale.x / 2 + space;
        let right = screenCenter.x + screenSize.width * Global.screenAdjustScale.x / 2 - space;
        let top = screenCenter.y + screenSize.height / 2 - space;//* Global.screenAdjustScale.y / 2;
        let bottom = screenCenter.y - screenSize.height / 2 + space;// * Global.screenAdjustScale.y / 2;

        let out = position.x > right || position.x < left || position.y > top || position.y < bottom;

        return !out;
    }

    public static getEnumName(enumType: any, value: number): string | undefined {
        // Loop through the keys of the enum
        for (let key in enumType) {
            // Check if the value matches the enum value
            if (enumType[key] === value) {
                return key;
            }
        }
        return undefined;
    }

    public static getEnumIndex(enumType: any, value: number): number {
        let index = -1;
        // Loop through the keys of the enum
        for (let key in enumType) {
            index++;
            // Check if the value matches the enum value
            if (enumType[key] === value) {
                return index;
            }
        }
        return index;
    }

    public static printError(error: Error, des?: string) {
        if (des) {
            console.error(des);
        }
        if (error) {
            console.error("堆栈信息:" + error.stack);
        }
    }

    public static secondsToTimeString(seconds: number): string {
        const h = Math.floor(seconds / 3600);
        const m = Math.floor((seconds % 3600) / 60);
        const s = Math.floor(seconds % 60);

        const hours = h < 10 ? '0' + h : h.toString();
        const minutes = m < 10 ? '0' + m : m.toString();
        const sec = s < 10 ? '0' + s : s.toString();

        return `${hours}:${minutes}:${sec}`;
    }

    static newSpriteCircleAnim(animSprite: Sprite, circleCount: number) {

        let rs = null;
        let promise = new Promise((resolve) => {
            rs = resolve;
        });

        let count = 0;

        let tw = tween(animSprite.node).by(0.5, { angle: -180 })
            .call(() => {
                count++;

                if (count >= circleCount) {

                    tween(animSprite.getComponent(UIOpacity))
                        .by(0.5, { opacity: -255 })
                        .call(() => rs())
                        .start();
                }
                else {
                    tw.start();
                }
            })
            .start();

        return promise;
    }

    static hex2color(hexColor: string) {
        const hex = hexColor.replace(/^#?/, "0x");
        const c = parseInt(hex);
        const r = c >> 16;
        const g = (65280 & c) >> 8;
        const b = 255 & c;
        return color(r, g, b, 255);
    };

    /**将该坐标同步目标的旋转变换 */
    static getRotatedPos(out: Vec3 | Vec2, target: Node, reverse = false) {
        // 旋转本地坐标
        let angle = target.angle; // 节点的旋转角度
        angle = reverse ? -angle : angle;
        let cosAngle = Math.cos(misc.degreesToRadians(angle));
        let sinAngle = Math.sin(misc.degreesToRadians(angle));
        out.x = out.x * cosAngle - out.y * sinAngle;
        out.y = out.x * sinAngle + out.y * cosAngle;
    }

    static getRandomInt(min: number, max: number): number {
        // 确保 min 小于 max
        if (min > max) {
            [min, max] = [max, min];  // 交换
        }

        // 返回范围内的随机整数，包括 min 和 max
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    /**
     * 加权随机取数组一个元素 
     * @param isAscending 等于true权重递增，下标越大越有概率
     * */
    static weightedRandomSelect(
        values: any[],
        isAscending: boolean = true // 默认权重递增
    ): number {
        if (values.length == 1) {
            return values[0];
        }
        // 根据数组下标计算权重
        let weights = values.map((_, index) => index * 2);
        weights[0] = 1;

        if (!isAscending) {
            // 如果方向为递减，则倒置权重
            let maxWeight = Math.max(...weights);
            weights = weights.map(weight => maxWeight - weight);
            weights[weights.length - 1] = 1;
        }

        // 计算总权重
        let totalWeight = weights.reduce((sum, weight) => sum + weight, 0);

        // 生成 [0, totalWeight) 范围的随机数
        let randomValue = Math.random() * totalWeight;

        // 根据随机值选择对应的数字
        let accumulatedWeight = 0;
        for (let i = 0; i < values.length; i++) {
            accumulatedWeight += weights[i];
            if (randomValue < accumulatedWeight) {
                return values[i];
            }
        }

        // 如果没有返回值，默认返回最后一个值
        return values[values.length - 1];
    }
}